
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
// 
//   http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
import { isTypedArray, clone, createHashMap, isArray, isObject, isArrayLike, hasOwn, assert, each, map, isNumber, isString, keys } from 'zrender/lib/core/util.js';
import { SOURCE_FORMAT_ORIGINAL, SERIES_LAYOUT_BY_COLUMN, SOURCE_FORMAT_UNKNOWN, SOURCE_FORMAT_KEYED_COLUMNS, SOURCE_FORMAT_TYPED_ARRAY, SOURCE_FORMAT_ARRAY_ROWS, SOURCE_FORMAT_OBJECT_ROWS, SERIES_LAYOUT_BY_ROW } from '../util/types.js';
import { getDataItemValue } from '../util/model.js';
import { BE_ORDINAL, guessOrdinal } from './helper/sourceHelper.js';
// @inner

var SourceImpl =
/** @class */
function () {
	function SourceImpl(fields) {
		this.data = fields.data || (fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []);
		this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN; // Visit config

		this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;
		this.startIndex = fields.startIndex || 0;
		this.dimensionsDetectedCount = fields.dimensionsDetectedCount;
		this.metaRawOption = fields.metaRawOption;
		var dimensionsDefine = this.dimensionsDefine = fields.dimensionsDefine;

		if (dimensionsDefine) {
			for (var i = 0; i < dimensionsDefine.length; i++) {
				var dim = dimensionsDefine[i];

				if (dim.type == null) {
					if (guessOrdinal(this, i) === BE_ORDINAL.Must) {
						dim.type = 'ordinal';
					}
				}
			}
		}
	}

	return SourceImpl;
}();

export function isSourceInstance(val) {
	return val instanceof SourceImpl;
}
/**
 * Create a source from option.
 * NOTE: Created source is immutable. Don't change any properties in it.
 */

export function createSource(sourceData, thisMetaRawOption, // can be null. If not provided, auto detect it from `sourceData`.
	sourceFormat) {
	sourceFormat = sourceFormat || detectSourceFormat(sourceData);
	var seriesLayoutBy = thisMetaRawOption.seriesLayoutBy;
	var determined = determineSourceDimensions(sourceData, sourceFormat, seriesLayoutBy, thisMetaRawOption.sourceHeader, thisMetaRawOption.dimensions);
	var source = new SourceImpl({
		data: sourceData,
		sourceFormat: sourceFormat,
		seriesLayoutBy: seriesLayoutBy,
		dimensionsDefine: determined.dimensionsDefine,
		startIndex: determined.startIndex,
		dimensionsDetectedCount: determined.dimensionsDetectedCount,
		metaRawOption: clone(thisMetaRawOption)
	});
	return source;
}
/**
 * Wrap original series data for some compatibility cases.
 */

export function createSourceFromSeriesDataOption(data) {
	return new SourceImpl({
		data: data,
		sourceFormat: isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL
	});
}
/**
 * Clone source but excludes source data.
 */

export function cloneSourceShallow(source) {
	return new SourceImpl({
		data: source.data,
		sourceFormat: source.sourceFormat,
		seriesLayoutBy: source.seriesLayoutBy,
		dimensionsDefine: clone(source.dimensionsDefine),
		startIndex: source.startIndex,
		dimensionsDetectedCount: source.dimensionsDetectedCount
	});
}
/**
 * Note: An empty array will be detected as `SOURCE_FORMAT_ARRAY_ROWS`.
 */

export function detectSourceFormat(data) {
	var sourceFormat = SOURCE_FORMAT_UNKNOWN;

	if (isTypedArray(data)) {
		sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;
	} else if (isArray(data)) {
		// FIXME Whether tolerate null in top level array?
		if (data.length === 0) {
			sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;
		}

		for (var i = 0, len = data.length; i < len; i++) {
			var item = data[i];

			if (item == null) {
				continue;
			} else if (isArray(item)) {
				sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;
				break;
			} else if (isObject(item)) {
				sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;
				break;
			}
		}
	} else if (isObject(data)) {
		for (var key in data) {
			if (hasOwn(data, key) && isArrayLike(data[key])) {
				sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;
				break;
			}
		}
	}

	return sourceFormat;
}
/**
 * Determine the source definitions from data standalone dimensions definitions
 * are not specified.
 */

function determineSourceDimensions(data, sourceFormat, seriesLayoutBy, sourceHeader, // standalone raw dimensions definition, like:
// {
//     dimensions: ['aa', 'bb', { name: 'cc', type: 'time' }]
// }
// in `dataset` or `series`
	dimensionsDefine) {
	var dimensionsDetectedCount;
	var startIndex; // PENDING: Could data be null/undefined here?
	// currently, if `dataset.source` not specified, error thrown.
	// if `series.data` not specified, nothing rendered without error thrown.
	// Should test these cases.

	if (!data) {
		return {
			dimensionsDefine: normalizeDimensionsOption(dimensionsDefine),
			startIndex: startIndex,
			dimensionsDetectedCount: dimensionsDetectedCount
		};
	}

	if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
		var dataArrayRows = data; // Rule: Most of the first line are string: it is header.
		// Caution: consider a line with 5 string and 1 number,
		// it still can not be sure it is a head, because the
		// 5 string may be 5 values of category columns.

		if (sourceHeader === 'auto' || sourceHeader == null) {
			arrayRowsTravelFirst(function (val) {
				// '-' is regarded as null/undefined.
				if (val != null && val !== '-') {
					if (isString(val)) {
						startIndex == null && (startIndex = 1);
					} else {
						startIndex = 0;
					}
				} // 10 is an experience number, avoid long loop.
			}, seriesLayoutBy, dataArrayRows, 10);
		} else {
			startIndex = isNumber(sourceHeader) ? sourceHeader : sourceHeader ? 1 : 0;
		}

		if (!dimensionsDefine && startIndex === 1) {
			dimensionsDefine = [];
			arrayRowsTravelFirst(function (val, index) {
				dimensionsDefine[index] = val != null ? val + '' : '';
			}, seriesLayoutBy, dataArrayRows, Infinity);
		}

		dimensionsDetectedCount = dimensionsDefine ? dimensionsDefine.length : seriesLayoutBy === SERIES_LAYOUT_BY_ROW ? dataArrayRows.length : dataArrayRows[0] ? dataArrayRows[0].length : null;
	} else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
		if (!dimensionsDefine) {
			dimensionsDefine = objectRowsCollectDimensions(data);
		}
	} else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
		if (!dimensionsDefine) {
			dimensionsDefine = [];
			each(data, function (colArr, key) {
				dimensionsDefine.push(key);
			});
		}
	} else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {
		var value0 = getDataItemValue(data[0]);
		dimensionsDetectedCount = isArray(value0) && value0.length || 1;
	} else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {
		if (process.env.NODE_ENV !== 'production') {
			assert(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');
		}
	}

	return {
		startIndex: startIndex,
		dimensionsDefine: normalizeDimensionsOption(dimensionsDefine),
		dimensionsDetectedCount: dimensionsDetectedCount
	};
}

function objectRowsCollectDimensions(data) {
	var firstIndex = 0;
	var obj;

	while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line

	if (obj) {
		return keys(obj);
	}
} // Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],
// which is reasonable. But dimension name is duplicated.
// Returns undefined or an array contains only object without null/undefined or string.

function normalizeDimensionsOption(dimensionsDefine) {
	if (!dimensionsDefine) {
		// The meaning of null/undefined is different from empty array.
		return;
	}

	var nameMap = createHashMap();
	return map(dimensionsDefine, function (rawItem, index) {
		rawItem = isObject(rawItem) ? rawItem : {
			name: rawItem
		}; // Other fields will be discarded.

		var item = {
			name: rawItem.name,
			displayName: rawItem.displayName,
			type: rawItem.type
		}; // User can set null in dimensions.
		// We don't auto specify name, otherwise a given name may
		// cause it to be referred unexpectedly.

		if (item.name == null) {
			return item;
		} // Also consider number form like 2012.

		item.name += ''; // User may also specify displayName.
		// displayName will always exists except user not
		// specified or dim name is not specified or detected.
		// (A auto generated dim name will not be used as
		// displayName).

		if (item.displayName == null) {
			item.displayName = item.name;
		}

		var exist = nameMap.get(item.name);

		if (!exist) {
			nameMap.set(item.name, {
				count: 1
			});
		} else {
			item.name += '-' + exist.count++;
		}

		return item;
	});
}

function arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {
	if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {
		for (var i = 0; i < data.length && i < maxLoop; i++) {
			cb(data[i] ? data[i][0] : null, i);
		}
	} else {
		var value0 = data[0] || [];

		for (var i = 0; i < value0.length && i < maxLoop; i++) {
			cb(value0[i], i);
		}
	}
}

export function shouldRetrieveDataByName(source) {
	var sourceFormat = source.sourceFormat;
	return sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS;
}